//! 提供了一个随机产生身份证号的工具
//!
//! 可以随机产生身份证号或者指定地区，生日来产生身份证号

use crate::codes::REGION_CODES;
use crate::ic::{compute_verify_code, IdentityCard};
use rand::{
    prelude::{IteratorRandom, SliceRandom},
    thread_rng, Rng,
};

const MAX_MONTHS: u16 = 12;
const LEAP_YEAR: [u16; 12] = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const NORMAL_YEAR: [u16; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

/// 判断是否闰年
fn is_leap(year: u16) -> bool {
    year % 4 == 0
}

/// 根据年月获取月的最大天数
fn get_max_days(year: u16, month: u16) -> u16 {
    if is_leap(year) {
        return LEAP_YEAR[month as usize - 1];
    } else {
        return NORMAL_YEAR[month as usize - 1];
    }
}

/// 获取一个随机的身份证结构
///
/// 如果两个参数为空字符串则认为是随机取值
pub fn generate_identitycard(loc: String, birthday: String) -> IdentityCard {
    let mut rng = thread_rng();
    let region_code: String;

    if loc.len() > 0 && loc.len() <= 6 {
        region_code = REGION_CODES
            .iter()
            .filter(|x| x.starts_with(&loc))
            .into_iter()
            .choose(&mut rng)
            .unwrap()
            .to_string();
    } else {
        region_code = REGION_CODES.choose(&mut rng).unwrap().to_string()
    }

    let mut year = 0 as u16;
    let mut month = 0 as u16;
    let mut day = 0 as u16;
    if birthday.len() == 4 {
        year = birthday.parse::<u16>().unwrap();
        month = rng.gen_range(1, MAX_MONTHS);
        day = rng.gen_range(1, get_max_days(year, month));
    } else if birthday.len() == 6 {
        year = birthday[..4].parse::<u16>().unwrap();
        month = birthday[4..].parse::<u16>().unwrap();
        day = rng.gen_range(1, get_max_days(year, month));
    } else if birthday.len() == 8 {
        year = birthday[..4].parse::<u16>().unwrap();
        month = birthday[4..6].parse::<u16>().unwrap();
        day = birthday[6..].parse::<u16>().unwrap();
    } else {
        year = rng.gen_range(1990, 1999);
        month = rng.gen_range(1, MAX_MONTHS);
        day = rng.gen_range(1, get_max_days(year, month));
    }

    let birthday_code = format!("{y:>04}{m:>02}{d:>02}", y = year, m = month, d = day);

    let seq_code = format!("{}", rng.gen_range(100, 999));
    let verify_code = compute_verify_code(&region_code, &birthday_code, &seq_code).to_string();
    let ic = IdentityCard {
        region: region_code,
        birthday: birthday_code,
        seq: seq_code,
        verify: verify_code,
    };
    ic
}
